#include "pch.h"

#define LL long long

Zobrist::Zobrist() {
	srand(time(0));
	for (int i = 0; i < 11; i++) {
		for (int j = 0; j < 11; j++) {
			for (int k = 0; k < 3; k++) {
				LL temp = rand_ll();
				random[i][j][k] = temp;
			}
		}
	}

	/*for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10 - i; j++) {
			for (int k = 0; k < 3; k++) {
				LL temp = rand_ll();
				random[i][j][k] = temp;
				random[10 - i][10 - j][k] = temp;
			}
		}
	}
	for (int i = 0; i < 5; i++) {
		for (int k = 0; k < 3; k++) {
			LL temp = rand_ll();
			random[i][10 - i][k] = temp;
			random[10 - i][i][k] = temp;
		}
	}
	for (int k = 0; k < 3; k++) {
		random[5][5][k] = rand_ll();
	}*/
}

long long Zobrist::rand_ll() {
	return rand() ^ ((LL)rand() << 15) ^ ((LL)rand() << 30) ^ ((LL)rand() << 45) ^ ((LL)rand() << 60);
}

Zobrist * Zobrist::getIns() {
	static Zobrist ins;

	return &ins;
}

long long Zobrist::hash(const Board & board) {
	long long ans = 0;
	int size = board.s();

	for (int i = 0; i < size; i++) {
		for (int j = 0; j < size; j++) {
			ans ^= random[i][j][board.get(i, j)];
		}
	}

	return ans;
}

long long Zobrist::position(int x, int y, int k) {
	return random[x][y][k];
}

long long Zobrist::position(int pos, int k) {
	int x = pos / 11;
	int y = pos % 11;
	if (x < 0 || x >= 11 || y < 0 || y >= 11) {
		throw std::exception("hash position out of range");
	}

	return random[x][y][k];
}

long long Zobrist::update(const Board & board, long long original, int x, int y, int newval) {
	return original ^ random[x][y][board.get(x, y)] ^ random[x][y][newval];
}

long long Zobrist::update(const Board & board, long long original, int pos, int newval) {
	return original ^ position(pos, board.get(pos)) ^ position(pos, newval);
}